package order

import (
	"api/internal/svc"
	"api/internal/types"
	"api/pb/good"
	"api/pb/order"
	"api/pkg/metadata"
	"context"
	"fmt"
	"github.com/dtm-labs/dtm/client/dtmgrpc"
	"github.com/lithammer/shortuuid/v3"
	"github.com/zeromicro/go-zero/core/logx"
)

type CreateOrderLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateOrderLogic {
	return &CreateOrderLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *CreateOrderLogic) CreateOrder(req *types.Order) (*types.Empty, error) {
	return l.CreateOrderWithDB(req) // 原始方式
	//return l.CreateOrderWithDTMSaga(req) // DTM Sega 方式
	//return l.CreateOrderWithDTMTcc(req) // DTM Tcc 方式
}

func (l *CreateOrderLogic) CreateOrderWithDB(req *types.Order) (*types.Empty, error) {
	userId, err := metadata.GetUserIDFromCtx(l.ctx)
	if err != nil {
		return &types.Empty{}, err
	}

	var orderGoods []*order.GoodInfo
	var okStockGoods []*good.GoodStock
	var failStockGoods []*good.GoodStock
	var orderTotal int64
	for _, g := range req.Goods {
		goodCost := g.Price * g.Count
		orderTotal += goodCost
		okStockGoods = append(okStockGoods, &good.GoodStock{GoodId: g.Id, GoodCount: g.Count})
		failStockGoods = append(failStockGoods, &good.GoodStock{GoodId: g.Id, GoodCount: -g.Count})
		orderGoods = append(orderGoods, &order.GoodInfo{GoodId: g.Id, GoodName: g.Name, GoodPrice: g.Price, GoodCount: g.Count, GoodCost: goodCost})
	}
	_, err = l.svcCtx.GoodRpc.BatchStock(l.ctx, &good.StockRequest{Stocks: okStockGoods})
	if err != nil {
		l.Logger.Errorf("CreateOrder GoodRpc BatchStock failed, err: %v", err)
		return &types.Empty{}, err
	}

	resp, err := l.svcCtx.OrderRpc.CreateOrder(l.ctx, &order.OrderInfo{UserId: userId, Goods: orderGoods, OrderTotal: orderTotal})
	if err != nil {
		l.Logger.Errorf("CreateOrder OrderRpc CreateOrder failed, err: %v", err)
		_, err = l.svcCtx.GoodRpc.BatchStock(l.ctx, &good.StockRequest{Stocks: failStockGoods})
		if err != nil {
			l.Logger.Errorf("CreateOrder GoodRpc BatchStock return failed, err: %v", err)
			return &types.Empty{}, err
		}
		return &types.Empty{}, err
	}
	l.Logger.Infof("create order success: user_id=%d, order_id=%d, order_goods=%v", userId, resp.OrderId, okStockGoods)
	return &types.Empty{}, err
}

func (l *CreateOrderLogic) CreateOrderWithDTMSaga(req *types.Order) (*types.Empty, error) {
	userId, err := metadata.GetUserIDFromCtx(l.ctx)
	if err != nil {
		return nil, err
	}
	fmt.Println(userId)

	var orderGoods []*order.GoodInfo
	var okStockGoods []*good.GoodStock
	var failStockGoods []*good.GoodStock
	var orderTotal int64
	for _, g := range req.Goods {
		goodCost := g.Price * g.Count
		orderTotal += goodCost
		okStockGoods = append(okStockGoods, &good.GoodStock{GoodId: g.Id, GoodCount: g.Count})
		failStockGoods = append(failStockGoods, &good.GoodStock{GoodId: g.Id, GoodCount: -g.Count})
		orderGoods = append(orderGoods, &order.GoodInfo{GoodId: g.Id, GoodName: g.Name, GoodPrice: g.Price, GoodCount: g.Count, GoodCost: goodCost})
	}

	dtmServer := l.svcCtx.Config.MicroService.GRPCEndPoint
	goodServer, err := metadata.GetRPCAddressFromEtcd(l.svcCtx.Config.GoodRpc.Etcd.Hosts, l.svcCtx.Config.GoodRpc.Etcd.Key)
	if err != nil {
		l.Logger.Errorf("CreateOrderWithDTMSaga get good grpc endpoint failed, err: %v", err)
		return &types.Empty{}, err
	}
	orderServer, err := metadata.GetRPCAddressFromEtcd(l.svcCtx.Config.OrderRpc.Etcd.Hosts, l.svcCtx.Config.OrderRpc.Etcd.Key)
	if err != nil {
		l.Logger.Errorf("CreateOrderWithDTMSaga get order grpc endpoint failed, err: %v", err)
		return &types.Empty{}, err
	}

	orderReq := &order.OrderInfo{UserId: userId, Goods: orderGoods, OrderTotal: orderTotal}
	stockReq := &good.StockRequest{Stocks: okStockGoods}

	gid := dtmgrpc.MustGenGid(dtmServer)
	saga := dtmgrpc.NewSagaGrpc(
		dtmServer, gid,
	).Add(
		orderServer+"/order.Order/OrderConfirm", orderServer+"/order.Order/OrderCancel", orderReq,
	).Add(
		goodServer+"/good.Good/BatchStockConfirm", goodServer+"/good.Good/BatchStockCancel", stockReq,
	)
	saga.RetryLimit = 4 // 最大重试次数

	err = saga.Submit()
	if err != nil {
		l.Logger.Errorf("CreateOrder submit dtm-server failed, err: %v", err)
		return nil, fmt.Errorf("submit data to  dtm-server err  : %+v \n", err)
	}
	return &types.Empty{}, nil
}

func (l *CreateOrderLogic) CreateOrderWithDTMTcc(req *types.Order) (*types.Empty, error) {
	userId, err := metadata.GetUserIDFromCtx(l.ctx)
	if err != nil {
		return nil, err
	}
	fmt.Println(userId)

	var orderGoods []*order.GoodInfo
	var okStockGoods []*good.GoodStock
	var failStockGoods []*good.GoodStock
	var orderTotal int64
	for _, g := range req.Goods {
		goodCost := g.Price * g.Count
		orderTotal += goodCost
		okStockGoods = append(okStockGoods, &good.GoodStock{GoodId: g.Id, GoodCount: g.Count})
		failStockGoods = append(failStockGoods, &good.GoodStock{GoodId: g.Id, GoodCount: -g.Count})
		orderGoods = append(orderGoods, &order.GoodInfo{GoodId: g.Id, GoodName: g.Name, GoodPrice: g.Price, GoodCount: g.Count, GoodCost: goodCost})
	}

	dtmServer := l.svcCtx.Config.MicroService.GRPCEndPoint
	goodServer, err := metadata.GetRPCAddressFromEtcd(l.svcCtx.Config.GoodRpc.Etcd.Hosts, l.svcCtx.Config.GoodRpc.Etcd.Key)
	if err != nil {
		l.Logger.Errorf("CreateOrderWithDTMSaga get good grpc endpoint failed, err: %v", err)
		return &types.Empty{}, err
	}
	orderServer, err := metadata.GetRPCAddressFromEtcd(l.svcCtx.Config.OrderRpc.Etcd.Hosts, l.svcCtx.Config.OrderRpc.Etcd.Key)
	if err != nil {
		l.Logger.Errorf("CreateOrderWithDTMSaga get order grpc endpoint failed, err: %v", err)
		return &types.Empty{}, err
	}

	orderReq := &order.OrderInfo{UserId: userId, Goods: orderGoods, OrderTotal: orderTotal}
	stockReq := &good.StockRequest{Stocks: okStockGoods}

	gid := shortuuid.New()
	fmt.Println("gid:", gid)
	err = dtmgrpc.TccGlobalTransaction(dtmServer, gid, func(tcc *dtmgrpc.TccGrpc) error {
		stockResp := &good.Empty{}  // 替换为实际的响应类型
		orderResp := &order.Empty{} // 替换为实际的响应类型

		// 执行库存扣减分支
		err := tcc.CallBranch(
			stockReq,
			goodServer+"/good.Good/BatchStockTry",
			goodServer+"/good.Good/BatchStockConfirm",
			goodServer+"/good.Good/BatchStockCancel",
			stockResp, // 不需要回复
		)

		if err != nil {
			return fmt.Errorf("库存扣减失败: %w", err)
		}

		// 执行订单创建分支
		err = tcc.CallBranch(
			orderReq,
			orderServer+"/order.Order/OrderTry",
			orderServer+"/order.Order/OrderConfirm",
			orderServer+"/order.Order/OrderCancel",
			orderResp,
		)

		if err != nil {
			return fmt.Errorf("订单创建失败: %w", err)
		}

		return nil
	})
	return &types.Empty{}, err
}
